<?php
/**
 * Copyright (C) 2013 Pablo Sepúlveda P. <psep.pentauc@gmail.com>
 * 
 * This file is part of gAbstract.
 * WarpIT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * gAbstract is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with gAbstract.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Clase abstracta que permite la abstracción de la DB.
 * 
 * @author psep
 * @version 1.0
 * @package gAbstract
 * @copyright Copyright (c) 2013 Pablo Sepúlveda P.
 * @license GNU GPLv3 or later
 * @link http://www.psep.cl
 */
abstract class ExecuteBean {
	
	/**
	 * Objeto DataBase
	 * 
	 * @var DataBase Object
	 */
	private $database;
	
	/**
	 * Objeto QueryBuilder
	 * 
	 * @var QueryBuilder Object
	 */
	private $query;

	/**
	 * Método que crea una instancia única de la
	 * clase DataBase.
	 * 
	 * @return database object
	 */
	private function getDatabase(){
		if($this->database == null){
			$this->database = new DataBase(DB_TYPE, DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS);
		}
		
		return $this->database;
	}
	
	/**
	 * Método que genera instancia previa
	 * para generación de Select.
	 */
	private function selectStatus(){
		$this->query = new QueryBuilder();
		$this->query->createSelect();
	}
	
	/**
	 * Método que genera instancia previa
	 * para generación de Insert.
	 */
	private function insertStatus(){
		$this->query = new QueryBuilder();
		$this->query->createInsert();
	}
	
	/**
	 * Método que genera instancia previa
	 * para generación de Update.
	 */
	private function updateStatus(){
		$this->query = new QueryBuilder();
		$this->query->createUpdate();
	}
	
	/**
	 * Método que genera instancia previa
	 * para generación de Delete.
	 */
	private function deleteStatus(){
		$this->query = new QueryBuilder();
		$this->query->createDelete();
	}
	
	/**
	 * Método que recibe un Objeto determinado y
	 * en base a su ID retorna el contenido de
	 * dicho objeto.
	 * 
	 * @param object
	 * @return object
	 */
	protected function load($object){
		$this->selectStatus();
		$this->query->select(ObjectUtil::getAttributesOfObject($object));
		$this->query->from(get_class($object));
		
		$data = ObjectUtil::validateId($object);
		
		if($data != null){
			$this->query->where($data[0]);
			$this->query->addParameter($data[1], $data[2]);
		}
		
		$array 	  = $this->getDatabase()->exeSelect($this->query);
		$stdClass = ObjectUtil::arrayToObject($array[0]);

		return ObjectUtil::cast($object, $stdClass);
	}
	
	/**
	 * Método que retorna una posible lista de objetos definidos
	 * por el objeto ingresado como parámetro ($object).
	 * 
	 * @param Object
	 * @return array $list Objects
	 */
	protected function exeList($object){
		$this->selectStatus();
		$this->query->select(ObjectUtil::getAttributesOfObject($object));
		$this->query->from(get_class($object));
		
		$data		= ObjectUtil::searchValueObject($object);
		$conditions = array();
		$values		= array();
		
		if(count($data) > 0){
			foreach ($data as $vector) {
				$conditions[]= $vector[0];
				$values[]	 = $vector[1];
			}
			
			if(count($conditions) > 0 && count($values) > 0){
				$this->query->andWhere($conditions);
				
				foreach ($values as $value) {
					$this->query->addParameter($value);
				}
			}
		}
		
		$this->query->orderBy(array(ObjectUtil::getIdName($object)), 1);
		
		$array  = $this->getDatabase()->exeSelect($this->query);
		$list	= array();
		
		foreach ($array as $stdObject) {
			$list[] = ObjectUtil::cast($object, $stdObject);
		}
		
		return $list;
	}
	
	/**
	 * Método que genera inserts mediante abstracción.
	 * Retorna true si lo(s) inserts son ejecutados
	 * correctamente y false si produce error.
	 * Las transacciones están habilitadas con
	 * commit y rollback de manera automática.
	 * Si el ID de algún objeto es nulo, activa la
	 * opción de autoincrement.
	 * 
	 * @param mixed (Object - Array Objects)
	 * @throws Exception
	 * @return boolean validation
	 */
	protected function create($object){
		if($object == null){
			throw new Exception("Error: Debe definir algún objeto o lista de objetos", 1);
		}else{
			$this->insertStatus();
			return $this->getDatabase()->executeCUD($this->query, ObjectUtil::objectToList($object));
		}
	}
	
	/**
	 * Método que genera updates mediante abstracción.
	 * Retorna true si lo(s) inserts son ejecutados
	 * correctamente y false si produce error.
	 * Las transacciones están habilitadas con
	 * commit y rollback de manera automática.
	 * Si el ID de algún objeto es nulo, activa la
	 * opción de autoincrement.
	 * 
	 * @param mixed (Object - Array Objects)
	 * @throws Exception
	 * @return boolean validation
	 */
	protected function update($object){
		if($object == null){
			throw new Exception("Error: Debe definir algún objeto o lista de objetos", 1);
		}else{
			$this->updateStatus();
			return $this->getDatabase()->executeCUD($this->query, ObjectUtil::objectToList($object));
		}
	}
	
	/**
	 * Método que permite la eliminación simple en base
	 * a los datos otorgados en el objeto o lista de objetos.
	 * 
	 * @param mixed (Object - Array Objects)
	 * @throws Exception
	 * @return boolean validation
	 */
	protected function delete($object){
		if($object == null){
			throw new Exception("Error: Debe definir algún objeto o lista de objetos", 1);
		}else{
			$this->deleteStatus();
			return $this->getDatabase()->executeCUD($this->query, ObjectUtil::objectToList($object));
		}
	}
	
	/**
	 * Método que ejecuta truncate en la tabla de
	 * la entidad correspondiente. Verifique si 
	 * su base de datos soporta dicha instrucción.
	 * 
	 * @param Object
	 * @return boolean validation
	 */
	protected function resetTable($object){
		return $this->getDatabase()->resetTable(get_class($object));
	}
	
	/**
	 * Método que mapea las tablas o los campos determinados
	 * de una tabla dependiendo del parámetro ingresado.
	 * Si no se ingresa el nombre de la tabla traerá el
	 * mapeo de todas las tablas, sino los campos de la
	 * tabla ingresada.
	 * 
	 * @param String $tableName
	 * @return array
	 */
	protected function mapping($tableName = null){
		$this->selectStatus();

		if($tableName == null){
			$this->query->select(array('TABLE_NAME'));
			$this->query->from('INFORMATION_SCHEMA.TABLES');
			$this->query->where('TABLE_SCHEMA = ?');
			$this->query->addParameter(DB_NAME, 4);
		}else{
			$fields = array('COLUMN_NAME', 'IS_NULLABLE', 'DATA_TYPE', 'CHARACTER_MAXIMUM_LENGTH AS MAXLENGTH', 'COLUMN_KEY');
			$this->query->select($fields);
			$this->query->from('INFORMATION_SCHEMA.COLUMNS');
			$this->query->andWhere(array('TABLE_SCHEMA = ?', 'TABLE_NAME = ?'));
			$this->query->addParameter(DB_NAME, 4);
			$this->query->addParameter($tableName, 4);
			$this->query->orderBy(array('ORDINAL_POSITION'), 0);
		}
		
		return $this->getDatabase()->exeSelect($this->query);
	}
	
	
}

?>
